package com.jrfid.smartcabinet.demo.ui.add_finger

import android.app.Application
import android.util.Base64
import android.view.View
import androidx.databinding.ObservableField
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.jrfid.devicemanager.library.CMDData
import com.jrfid.devicemanager.library.DeviceType
import com.jrfid.devicemanager.library.DevicesManager
import com.jrfid.devicemanager.library.packet.FingerVeinPacketData
import com.jrfid.smartcabinet.demo.R
import com.jrfid.smartcabinet.demo.base.BaseViewModel
import com.jrfid.smartcabinet.demo.db.AppDatabase
import com.jrfid.smartcabinet.demo.db.entity.FingerInfoEntity
import com.jrfid.smartcabinet.demo.utils.Config
import com.xgzx.veinmanager.VeinApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.max

class AddFingerViewModel(application: Application, navController: NavController) : BaseViewModel(application, navController) {

    val tipsText = ObservableField("")

    //    private var devHandle: Long = -1
    private val charaPkgStep = 40

    private val listener = object : DevicesManager.OnDeviceDataCallback {

        override fun onDataReceived(deviceType: DeviceType, address: Byte, byteArray: ByteArray) {
            if (deviceType == DeviceType.FingerVein) {
                if (byteArray.size == 24) {
                    val model = FingerVeinPacketData(byteArray)
                    when (model.cmd) {
                        CMDData.FingerXGV5.CMD_CONNECT_DEVICE -> {
                            if (model.isSuccess()) {
                                //设备连接成功
                                LogUtils.i("指静脉连接成功")
                                fingerConnectJobMap[address]?.cancel()
                                DevicesManager.instance.sendData(deviceType = deviceType, address = address, byteArray = CMDData.FingerXGV5.getFingerCharaData())
                            } else {
                                LogUtils.i("指静脉连接失败")
                                connectFinger(address)
                            }
                        }
                        CMDData.FingerXGV5.CMD_GET_CHARA -> {
                            when (model.data[0]) {
                                CMDData.FingerXGV5.RESULT_SUCCESS -> {
                                    LogUtils.i("指静脉特征值获取成功")
                                    val pkgSize = (model.data[1].toInt() and 0xff) + ((model.data[2].toInt() and 0xff) shl 8)
                                    getCharaData(address, pkgSize)
                                }
                                CMDData.FingerXGV5.RESULT_ERR_FAIL -> {
                                    LogUtils.i("指静脉特征值获取失败")
                                    DevicesManager.instance.sendData(deviceType = deviceType, address = address, byteArray = CMDData.FingerXGV5.getFingerCharaData())
                                }
                                CMDData.FingerXGV5.RESULT_INPUT_FINGER -> {
                                    LogUtils.i("请放置手指")
                                }
                                CMDData.FingerXGV5.RESULT_OUTPUT_FINGER -> {
                                    LogUtils.i("请移开手指")
                                }
                            }
                        }
                        CMDData.FingerXGV5.CMD_FINGER_STATUS -> {
                            if (model.isSuccess()) {
                                LogUtils.i("手指状态获取成功")
                                when (model.data[1]) {
                                    0x00.toByte() -> {
                                        //无手指
                                        LogUtils.i("无手指")
                                        tipsText.set(getString(R.string.text_finger_in))
                                        DevicesManager.instance.sendData(deviceType = deviceType, address = address, byteArray = CMDData.FingerXGV5.getFingerCharaData())
                                    }
                                    0x01.toByte() -> {
                                        //有手指
                                        LogUtils.i("有手指")
                                        DevicesManager.instance.sendData(
                                            deviceType = DeviceType.FingerVein,
                                            address = address,
                                            CMDData.FingerXGV5.getFingerState()
                                        )
                                    }
                                }
                            } else {
                                LogUtils.i("手指状态获取失败")
                                DevicesManager.instance.sendData(
                                    deviceType = DeviceType.FingerVein,
                                    address = address,
                                    CMDData.FingerXGV5.getFingerState()
                                )
                            }
                        }
                    }
                } else {
                    if (isOnGetCharaMap[address] == true) {
                        LogUtils.i("得到特征值数据")
                        val currentPkgSize = currentPkgSizeMap[address]
                        if (currentPkgSize != null && byteArray.size >= currentPkgSize + 2) {
                            //指静脉特征值数据
                            val data = ByteArray(currentPkgSize)
                            System.arraycopy(byteArray, 0, data, 0, data.size)
                            val checkSum2 = ((byteArray[currentPkgSize].toInt() and 0xff) + (byteArray[currentPkgSize + 1].toInt() and 0xff shl 8)).toShort()
                            val checkSum1 = CMDData.FingerXGV5.checkSum(data, 0, data.size)
                            if (checkSum1 == checkSum2) {
                                getNextCharaData(address, data)
                            } else {
                                getCurrentCharaData(address)
                            }
                        } else {
                            getCurrentCharaData(address)
                        }
                    }
                }
            }
        }

        override fun onDataSend(deviceType: DeviceType, address: Byte, byteArray: ByteArray) {

        }

    }

    private val pkgNumMap = hashMapOf<Byte, Int>()
    private val pkgDataMap = hashMapOf<Byte, ByteArray>()
    private val lastPkgSizeMap = hashMapOf<Byte, Int>()
    private val currentNumMap = hashMapOf<Byte, Int>()
    private val currentOffsetMap = hashMapOf<Byte, Int>()
    private val currentPkgSizeMap = hashMapOf<Byte, Int>()
    private val isOnGetCharaMap = hashMapOf<Byte, Boolean>()
    private fun getCharaData(address: Byte, pkgSize: Int) {
        isOnGetCharaMap[address] = true
        pkgDataMap[address] = byteArrayOf()
        currentNumMap[address] = 0
        val pkgNum = pkgSize / charaPkgStep
        pkgNumMap[address] = pkgNum
        val lastPkgSize = pkgSize % charaPkgStep
        lastPkgSizeMap[address] = lastPkgSize
        val currentOffset = 0
        currentOffsetMap[address] = currentOffset
        val currentPkgSize = if (pkgNum > 0) charaPkgStep else lastPkgSize
        currentPkgSizeMap[address] = currentPkgSize
        DevicesManager.instance.sendData(
            deviceType = DeviceType.FingerVein,
            address = address,
            CMDData.FingerXGV5.readData(CMDData.FingerXGV5.CMD_GET_CHARA, currentOffset, currentPkgSize)
        )
    }

    private fun getCurrentCharaData(address: Byte) {
        val currentOffset = currentOffsetMap[address] ?: 0
        val currentPkgSize = currentPkgSizeMap[address] ?: 0
        DevicesManager.instance.sendData(
            deviceType = DeviceType.FingerVein,
            address = address,
            CMDData.FingerXGV5.readData(CMDData.FingerXGV5.CMD_GET_CHARA, currentOffset, currentPkgSize)
        )
    }

    private fun getNextCharaData(address: Byte, data: ByteArray) {
        val tempData = pkgDataMap[address] ?: byteArrayOf()
        var currentOffset = currentOffsetMap[address] ?: 0
        var currentPkgSize = currentPkgSizeMap[address] ?: 0
        val pkgData = ByteArray(tempData.size + data.size)
        System.arraycopy(tempData, 0, pkgData, 0, tempData.size)
        System.arraycopy(data, 0, pkgData, currentOffset, currentPkgSize)
        currentOffset += currentPkgSize
        val currentNum = (currentNumMap[address] ?: 0) + 1
        val pkgNum = pkgNumMap[address] ?: 0
        val lastPkgSize = lastPkgSizeMap[address] ?: 0
        if (currentNum == pkgNum) {
            if (lastPkgSize == 0) {
                isOnGetCharaMap[address] = true
                val chara = String(Base64.encode(pkgData, Base64.NO_WRAP))
                LogUtils.d("特征值：${chara}")
                tipsText.set(getString(R.string.text_finger_out))
                testAddChara(chara)
                DevicesManager.instance.sendData(
                    deviceType = DeviceType.FingerVein,
                    address = address,
                    CMDData.FingerXGV5.getFingerState()
                )
            } else {
                currentPkgSize = lastPkgSize
                pkgDataMap[address] = pkgData
                currentNumMap[address] = currentNum
                currentOffsetMap[address] = currentOffset
                currentPkgSizeMap[address] = currentPkgSize
                DevicesManager.instance.sendData(
                    deviceType = DeviceType.FingerVein,
                    address = address,
                    CMDData.FingerXGV5.readData(CMDData.FingerXGV5.CMD_GET_CHARA, currentOffset, currentPkgSize)
                )
            }
        } else if (currentNum < pkgNum) {
            currentPkgSize = charaPkgStep
            pkgDataMap[address] = pkgData
            currentNumMap[address] = currentNum
            currentOffsetMap[address] = currentOffset
            currentPkgSizeMap[address] = currentPkgSize
            DevicesManager.instance.sendData(
                deviceType = DeviceType.FingerVein,
                address = address,
                CMDData.FingerXGV5.readData(CMDData.FingerXGV5.CMD_GET_CHARA, currentOffset, currentPkgSize)
            )
        } else {
            isOnGetCharaMap[address] = false
            val chara = String(Base64.encode(pkgData, Base64.NO_WRAP))
            val chara2 = VeinApi.FVEncodeBase64(pkgData,pkgData.size.toLong())
            LogUtils.d("特征值1：${chara}")
            LogUtils.d("特征值2：${chara2}")
            tipsText.set(getString(R.string.text_finger_out))
            testAddChara(chara)
            DevicesManager.instance.sendData(
                deviceType = DeviceType.FingerVein,
                address = address,
                CMDData.FingerXGV5.getFingerState()
            )
        }
    }

    private val charaList = arrayListOf<String>()
    private fun testAddChara(chara: String) {
        if (charaList.size < 2) {
            charaList.add(chara)
        } else if (charaList.size == 2) {
            charaList.add(chara)
            val temp = DevicesManager.instance.createFingerVeinCharaTemp(charaList)
            if (temp != null) {
                LogUtils.d("特征值模板生成成功")
                DevicesManager.instance.addCharaTempToSearchLib(temp)
            } else {
                LogUtils.d("特征值模板生成失败")
            }
        } else if (charaList.size == 3) {
            charaList.clear()
            val temp = DevicesManager.instance.searchFingerVeinTemp(chara)
            if (temp != null) {
                LogUtils.d("比对成功，查询到特征值模板")
            } else {
                LogUtils.d("比对失败")
            }
        }
    }


    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        DevicesManager.instance.addOnDeviceDataListener(listener)
        val list = Config.getCabinetList()
        if (list.isEmpty()) {
            tipsText.set(getString(R.string.text_config_cabinet_info))
            ToastUtils.showShort(getString(R.string.text_config_cabinet_info))
        } else {
            //获取主柜信息
            list.forEach {
                it.address.get()?.toIntOrNull()?.toByte()?.let {
                    connectFinger(it)
                }
            }
            val fingerList = AppDatabase.instance.getFingerInfoDao().queryAll().map { it.finger }
            DevicesManager.instance.createFingerSearchLib(fingerList.toMutableList())
//            val info = list[0]
//            devHandle = VeinApi.FVConnectDev("IP:${info.fingerIP.get()},PORT:${info.fingerPort.get()}", "00000000")
//            if (devHandle > 0) {
//                LogUtils.dTag(TAG, "连接成功")
////                thread.start()
//            } else {
//                LogUtils.dTag(TAG, "连接失败")
//                ToastUtils.showLong(getString(R.string.text_connect_error))
//                tipsText.set(getString(R.string.text_connect_error))
//            }
        }
    }

    private val fingerConnectJobMap = hashMapOf<Byte, Job>()
    private fun connectFinger(address: Byte) {
        var job = if (fingerConnectJobMap.containsKey(address)) {
            fingerConnectJobMap[address]
        } else {
            null
        }
        job?.cancel()
        DevicesManager.instance.sendData(deviceType = DeviceType.FingerVein, address = address, byteArray = CMDData.FingerXGV5.connectDevice())
        job = viewModelScope.launch(Dispatchers.IO) {
            delay(2000)
            connectFinger(address)
        }
        fingerConnectJobMap[address] = job
    }

//    private var thread = object : Thread() {
//        override fun run() {
//            super.run()
//            var searchHandle: Long? = null
//            try {
//                var temp = ""
//                var charaNum = 0
//                //算法库容量
//                var libSize = 50
//                //算法库当前已使用容量
//                var currentSize = 0
//                while (true) {
//                    if (!isInterrupted) {
//                        if (searchHandle == null || currentSize == libSize) {
//                            val fingerCharaList = AppDatabase.instance.getFingerInfoDao().queryAll()
//                            if (searchHandle == null) {
//                                //初始化创建
//                                libSize = max(fingerCharaList.size + 1, 50)
//                                currentSize = fingerCharaList.size
//                            } else {
//                                //算法库容量已满，重新创建更大的算法库
//                                VeinApi.FVDestroyVeinLib(searchHandle)
//                                libSize += 50
//                                currentSize = fingerCharaList.size
//                            }
//                            searchHandle = VeinApi.FVCreateVeinLib(libSize.toLong())
//                            if (searchHandle <= 0) {
//                                LogUtils.dTag(TAG, "算法库创建失败：${searchHandle}")
//                                searchHandle = null
//                                sleep(1000)
//                                continue
//                            } else {
//                                LogUtils.dTag(TAG, "算法库创建成功")
//                                fingerCharaList.forEach {
//                                    val userId = VeinApi.FVGetNullID(searchHandle)
//                                    val code = VeinApi.FVImportVeinTemp(searchHandle, userId, it.finger)
//                                    if (code == 0L) {
//                                        LogUtils.dTag(TAG, "用户${userId}模板导入算法库成功")
//                                    } else {
//                                        LogUtils.dTag(TAG, "用户${userId}模板导入算法库失败${code}")
//                                    }
//                                }
//                            }
//                            //检测手指
//                            val code = VeinApi.FVCheckFinger(devHandle)
//                            if (code <= 0L) {
//                                //无手指
//                                tipsText.set(getString(R.string.text_login_by_finger_tips))
//                            }
//                        }
//                        val sChara = VeinApi.FVGetVeinChara(devHandle, 6000) //通过指静脉设备采集特征，等待手指放入超时为6秒
//                        if (sChara.length < 10) {
//                            //获取失败
//                            val error = sChara.toIntOrNull()
//                            val text = if (error == -16) {
//                                getString(R.string.text_finger_vein_not_support)
//                            } else if (error == -11) {
//                                getString(R.string.text_finger_vein_no_fingers)
//                            } else if (error == -17) { //特征采集失败可以继续采集下一次
//                                getString(R.string.text_finger_vein_incorrect)
//                            } else {
//                                getStringFormat(R.string.text_finger_vien_error, error ?: 0)
//                            }
//                            tipsText.set(text)
//                            LogUtils.dTag(TAG, text)
//                            sleep(1000)
//                            continue
//                        } else {
//                            //获取成功
//                            LogUtils.dTag(TAG, "特征值${charaNum}获取成功：${sChara}")
//                            //先判断该手指时候录入
//                            val userId = VeinApi.FVSearchUser(searchHandle, sChara, 2)
//                            if (userId > 0) {
//                                //识别成功,该手指已经录入
//                                tipsText.set(getString(R.string.text_finger_vein_registered))
//                                ToastUtils.showLong(getString(R.string.text_finger_vein_registered))
//                                sleep(1000)
//                                //检测手指拿开
//                                while (true) {
//                                    if (!isInterrupted) {
//                                        val code = VeinApi.FVCheckFinger(devHandle)
//                                        if (code <= 0L) {
//                                            //无手指
//                                            tipsText.set(getString(R.string.text_finger_vein_retry))
//                                            break
//                                        } else {
//                                            sleep(1000)
//                                        }
//                                    }
//                                }
//                            } else {
//                                //有效的数据
//                                temp = VeinApi.FVAddCharaToTemp(temp, sChara, null, 0)
//                                if (temp.length < 10) {
//                                    tipsText.set(getStringFormat(R.string.text_finger_vein_temp_error, temp))
//                                } else {
//                                    LogUtils.dTag(TAG, "模板特征值${charaNum}添加成功：${temp}")
//                                    charaNum++
//                                }
//                            }
//                        }
//                        if (charaNum == 3) {
//                            //成功获取3次特征值，保存到数据库
//                            AppDatabase.instance.getFingerInfoDao().insert(FingerInfoEntity().apply { this.finger = temp })
//                            tipsText.set(getString(R.string.text_finger_vein_register_successfully))
//                            ToastUtils.showShort(getString(R.string.text_finger_vein_register_successfully))
//                            //导入模板到算法库
//                            val userId = VeinApi.FVGetNullID(searchHandle)
//                            val code = VeinApi.FVImportVeinTemp(searchHandle, userId, temp)
//                            if (code == 0L) {
//                                LogUtils.dTag(TAG, "用户${userId}模板导入算法库成功")
//                            } else {
//                                LogUtils.dTag(TAG, "用户${userId}模板导入算法库失败${code}")
//                            }
//                            charaNum = 0
//                            temp = ""
//                            currentSize++
//                            //检测手指拿开
//                            while (true) {
//                                if (!isInterrupted) {
//                                    val code = VeinApi.FVCheckFinger(devHandle)
//                                    if (code <= 0L) {
//                                        //无手指
//                                        tipsText.set(getString(R.string.text_login_by_finger_tips))
//                                        break
//                                    } else {
//                                        sleep(1000)
//                                    }
//                                }
//                            }
//                        }
//                    }
//                }
//            } catch (e: Exception) {
//                e.printStackTrace()
//            } finally {
//                searchHandle?.let {
//                    VeinApi.FVDestroyVeinLib(searchHandle)
//                }
//            }
//        }
//    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
        DevicesManager.instance.removeOnDeviceDataListener(listener)
//        val code = VeinApi.FVCloseDev(devHandle)
//        if (code == 0L) {
//            LogUtils.dTag(TAG, "指静脉断开连接")
//        }
    }


    fun onClickBtnBack(view: View) {
//        thread.interrupt()
        navController.navigateUp()
    }
}